<!DOCTYPE html>

<!--
  Google HTML5 slide template

  Authors: Luke Mahé (code)
           Marcin Wichary (code and design)
           
           Dominic Mazzoni (browser compatibility)
           Charles Chen (ChromeVox support)

  URL: http://code.google.com/p/html5slides/
-->

<html>
  <head>
    <title>Building Games With Google Technologies</title>

    <meta charset='utf-8'>
    <script src='static/slides.js'></script>
    <script src='static/jquery-1.6.4.js'></script>
    <script>
      var first = true;
      function loadgame(game) {
          var playn101 = $("#playn101")[0];
          playn101.contentWindow.platform_0.graphics.rootLayer.clear_0();
          playn101.contentWindow.platform_0.keyboard.listener.this$0.current = game;
          playn101.contentWindow.platform_0.keyboard.listener.this$0.games[game].init_0();
      }
      setTimeout(function() {
        $("#playn101")[0].contentWindow.platform_0.keyboard.listener.this$0.games[6].init_0(); // preload I.java bug
        first = false;
      }, 3000);
      function ongameenter(el, game) {
        var playn = document.getElementById('playn-root');
        playn.parentNode.removeChild(playn);
        el.appendChild(playn);
        if (first) {
	  setTimeout(function() {
              loadgame(game);
	  }, 4000); // workaround no onload event for gwt dynamic iframe
          first = false;
        } else {
          loadgame(game);
        }
      }
    </script>
  </head>
  
  <style>
    .blue {
    color: skyBlue;
    }

    .white {
    color: white;
    text-shadow: -2px 0 grey, 0 2px grey, 2px 0 grey, 0 -2px grey;
    }

    #playn-container {
    display: none;
    }

    #playn-root {
    margin: auto;
    margin-top: 50px;
    }

    a {
    text-decoration: none;
    }

    .slides > article .selflink {
    font-size: 24px;
    display: block;
    position: absolute;
    left: 15px;
    bottom: 40px;
    }

    .playn {
    margin-left: 5px;
    }

    .swiss { font-weight: bold; background: #DD4B39; color: white;
    border-radius: 5px; padding: 5px; }
    
    .angrybird {
    padding-top: 20px;
    }
    
    .photo {
    position: absolute;
    right: 100px;
    top: 350px;
    border-radius: 10px;
    }
  </style>

  <body style='display: none'>

    <section class='slides layout-regular template-gdd2011'>
            
      <article>
        <h1>Building Games With Google Technologies</h1>
        <p>
          Johan Euphrosine
	  <br>
          Nov 1, 2011
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>About Me</h3>
	<p>
	  <ul>
	    <img class="photo" src="/static/images/proppy.jpg">
	    <li>Johan Euphrosine &lt;proppy&#64;google.com&gt;</li>
	    <li>Google  <span class="swiss">Zurich</span></li>
	    <li>Developer Programs Engineer</li>
	    <li>Supporting App Engine <img src="/static/images/appengine_final.png" height="24px"> Developer Community</li>
	    <li><a href="http://profiles.google.com/proppy">profiles.google.com/proppy</a></li>
	  </ul>
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>Remember Angry Birds?</h3>
	<p>
	  <img class="centered angrybird" width="581px" src="/static/images/angrybird.jpg">
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>Leverage Google Open Technologies and Platforms</h3>
	<p>
	  <ul>
	    <li>Chrome <img class="logo" src="/static/images/chrome.jpg" height="34px"></li>
	    <li>Android <img class="logo" src="/static/images/android_vector.jpg" height="40px"></li>
	    <li>Google+ <img class="logo" src="/static/images/google_plus_logo.jpg" height="34px"></li>
	    <li>Google Web Toolkit <img class="logo" src="/static/images/gwt-logo.png" height="34px"></li>
	    <li>App Engine <img class="logo" src="/static/images/appengine_final.png" height="34px"></li>
	    <li>HTML <img class="logo" src="/static/images/html5.png" height="30px"></li>
	  </ul>
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>Build with the Play <img class="logo" height="28px" src="/static/images/n.png"> library</h3>
	<p>
	  <ul>
	    <li>Cross platform game library</li>
	    <li>Write once <img class="logo" src="/static/images/duke.png" height="40px">, and deliver on N Platforms <img class="logo" src="/static/images/java.png" height="50px"><img class="logo" src="/static/images/html5.png" height="30px"><img class="logo" src="/static/images/android_vector.jpg" height="30px"><img class="logo" src="/static/images/adobe_flash_logo.gif" height="30px"></li>
	    <li>Free and Open Source: Apache License 2.0</li>
	    <li><a href="http://developers.google.com/playn/">developers.google.com/playn/</a></li>
	    <li>Already forked by game studios <a href="https://github.com/threerings/playn">github.com/threerings/playn</a></li>
	  </ul>
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>Hardware acceleration</h3>
	<p>
	  <ul>
	    <li>WebGL on <img class="logo" src="/static/images/chrome.jpg" height="30px"></li>
	    <li>GLES and Canvas on <img class="logo" src="/static/images/android_vector.jpg" height="40px"></li>
	    <li>CSS3 on Safari</li>
	    <li>Canvas on IE9</li>
	  </ul>
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
        <h3>
	  Each platform implements the same set of APIs
	</h3>
	<p>
<ul>
  <li>For IO system
    <pre>
  import static PlayN.*;
  graphics()
  audio()
  net()
  pointer()</pre>
  </li>
  <li>And Assets management
    <pre>
  assetManager()
    .getImage()
    .getSound()
    .getText()</pre>
  </li>
</ul>
</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
        <h3>
          And You implement the Game Interface
        </h3>
	<section>
	  <pre>
package playn.core;

public interface Game {

  void init();

  void update(float delta);

  void paint(float alpha);

  int updateRate();
}</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h2>Play<img class="playn" height="39px" src="/static/images/n.png"> 101</h2>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
        <h3>
          Every game should start with a <span class="blue">blue</span> sky
        </h3>
	<section>
	  <pre>
public class MyGame implements Game {

  @Override
  public void init() {
    int width = 640;
    int height = 480;
    CanvasImage bgImage = graphics().createImage(width, height);
    Canvas canvas = bgImage.canvas();
    canvas.setFillColor(0xff87ceeb);
    canvas.fillRect(0, 0, width, height);
    ImageLayer bg = graphics().createImageLayer(bgImage);
    graphics().rootLayer().add(bg);
  }
}</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 0)">
        <h3>
          Every game should start with a <span class="blue">blue</span> sky
        </h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  And some <span class="white">white</span> clouds
	</h3>
	<section>
	  <pre>
Image cloudImage = assetManager().getImage("images/cloud.png");
ImageLayer cloud = graphics().createImageLayer(cloudImage);
graphics().rootLayer().add(cloud);
float x = 24.0f;
float y = 3.0f;
cloud.setTranslation(x, y);</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 1)">
	<h3>
	  And some <span class="white">white</span> clouds
	</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  Layer can be animated
	</h3>
	<section>
	  <pre>
@Override
public void paint(float delta) {
  x += 0.1f * delta;
  if (x > bgImage.width() + cloudImage.width()) {
    x = -cloudImage.width();
  }
  cloud.setTranslation(x, y);
}</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 2)">
	<h3>Layer can be animated</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  You can hook on click event and create new layers
	</h3>
	<section>
	  <pre>
Image ballImage = assetManager().getImage("images/ball.png");
GroupLayer ballsLayer = graphics().createGroupLayer();
graphics().rootLayer().add(ballsLayer);
pointer().setListener(new Pointer.Adapter() {
  @Override
  public void onPointerEnd(Pointer.Event event) {
    ImageLayer ball = graphics().createImageLayer(ballImage);
    ball.setTranslation(event.x(), event.y());
    ballsLayer.add(ball);
  }
});</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 3)">
	<h3>
	  You can listen for click even and create new layers
	</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  import org.jbox2d.*;
	</h3>
	<section>
	  <pre>
float physUnitPerScreenUnit = 1 / 26.666667f;
Vec2 gravity = new Vec2(0.0f, 10.0f);
world = new World(gravity, true);
ballsLayer.setScale(1f / physUnitPerScreenUnit);
</pre>
<div class="build"><pre>
class Ball {
  public initPhysics() {
    BodyDef bodyDef = new BodyDef();
    bodyDef.type = BodyType.DYNAMIC;
    body = world.createBody(bodyDef);
    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = new CircleShape();
    fixtureDef.circleShape.m_radius = 0.5f;
    fixtureDef.density = 1.0f;
    body.createFixture(fixtureDef);
  }
}</pre></div>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 4)">
	<h3>
	  And eventually some physics will come in
	</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  Don't forget to add the ground!
	</h3>
	<section>
	  <pre>
float worldWidth = physUnitPerScreenUnit * width;
float worldHeight = physUnitPerScreenUnit * height;
Body ground = world.createBody(new BodyDef());
PolygonShape groundShape = new PolygonShape();
groundShape.setAsEdge(new Vec2(0, worldHeight),
                      new Vec2(worldWidth, worldHeight));
ground.createFixture(groundShape, 0.0f);</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 5)">
	<h3>
	  Don't forget to add the ground!
	</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  Let's add more blocks
	</h3>
	<section>
	  <pre>
Image blockImage = assetManager().getImage("images/block.png");    
float blockWidth = blockImage.width()*physUnitPerScreenUnit;
float blockHeight = blockImage.height()*physUnitPerScreenUnit;
GroupLayer blocksLayer = graphics().createGroupLayer();
blocksLayer.setScale(1f / physUnitPerScreenUnit);
Body blocksBody = world.createBody(new BodyDef());
</pre>
<div class="build"><pre>
  for (int i = 0; i < 4; i++) {
    ImageLayer block = graphics().createImageLayer(blockImage);
    block.setTranslation((1+2*i)*blockWidth, worldHeight-height);
    blocksLayer.add(block);
    PolygonShape shape = new PolygonShape();
    shape.setAsBox(blockWidth/2f, blockHeight/2f,
		   block.transform().translation(), 0f);
    blocksBody.createFixture(shape, 0.0f);
  }
}</pre></div>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 6)">
	<h3>
	  Let's add more blocks
	</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  And some nails
	</h3>
	<section>
	  <pre>
public void initNails() {
  for (int x = 100; x < bgImage.width() - 100; x += 50) {
    for (int y = 150; y < 450; y+= 100) {
	canvas.setFillColor(0xffaaaaaa);
	canvas.fillCircle(x, y, radius);
	CircleShape circleShape = new CircleShape();
	circleShape.m_radius = 5f*physUnitPerScreenUnit;
	circleShape.m_p.set(x*physUnitPerScreenUnit,
                            y*physUnitPerScreenUnit);
	FixtureDef fixtureDef = new FixtureDef();
	fixtureDef.shape = circleShape;
	fixtureDef.restitution = 0.6f;
	ground.createFixture(fixtureDef);
    }
  }
}</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 7)">
	<h3>
	  パチンコ!
	</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  The only thing missing is a score
	</h3>
	<section>
	  <pre>
int[] pointsTable = {-10, 10, 50, 10, -10};
int points = 0;
@Override
public void update(float delta) {
  for (Ball ball : balls) {
    Vector pos = ball.layer.transform().translation();
    if (pos.y() >= scoringHeight) {
      int slot = (int)pos.x() / (int)scoringWidth;
      points += pointsTable[slot];
      points = Math.max(0, points);
      ballsLayer.remove(ball.layer);
      world.destroyBody(ball.body);
      removeBalls.add(ball);
    }
  }
}</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 8)">
	<h3>
	  The only thing missing is a score
	</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  Weird... it doesn't update. See how we draw the score?
	</h3>
	<section>
	  <pre>
CanvasImage pointsImage;
ImageLayer pointsLayer;
void initPoints() {
  pointsImage = graphics().createImage(width, 50);
  pointsLayer = graphics().createImageLayer(pointsImage);
  pointsLayer.setScale(3f);
  graphics().rootLayer().add(pointsLayer);
}
public void paint(float delta) {
  String s = Integer.toString(points);
  pointsImage.canvas().clear();
  pointsImage.canvas().setFillColor(0xff000000);
  pointsImage.canvas().drawText(s, 10f, 20f);
}
</pre>
	</section>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  Is there a bug in PlayN.Canvas.drawText?
	</h3>
	<p>
	  <ul class="build">
	    <li>Let's try it in Java</li>
	    <li>That seems to work perfectly fine here!</li>
	    <li>Let's <a href="http://code.google.com/p/playn/issues/entry" target="_new">report</a> it!</li>
	    <li>Feeling any better ?</li>
	  </ul>
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  Let's use a bitmap font, and do sprites <img src="/static/images/font.png" height="20">
	</h3>
	<p>
	  <pre class="build"><span>Image pointsFontImage;
void init() {
  pointsLayer = graphics().createGroupLayer();
  pointsLayer.setScale(3.0f, 3.0f);
  pointsFontImage = assetManager().getImage("images/font.png");
  graphics().rootLayer().add(pointsLayer);
}</span><span>
void update {
  float x = 0f;
  pointsLayer.clear();
  for (char c : Integer.toString(points).toCharArray()) {
    ImageLayer digit = graphics().createImageLayer(pointsFontImage);
    digit.setSourceRect((c - '0' + 9) % 10; * 16, 0, 16, 16);
    pointsLayer.add(digit);      
    digit.setTranslation(x, 0f);
    x += 16f;
  }
}</span></pre>
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article onslideenter="ongameenter(this, 9)">
	<h3>
	  Better!
	</h3>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	  Homework
	</h3>
	<p>
	  <ul>
	    <li>Push the score to App Engine using <code>net()</code> submodule</li>
	    <li>Make it pretty</li>
	    <li>Add player thumbnail using <code>Google+</code> API</li>
	    <li>Download Play<img class="playn" height="24px" src="/static/images/n.png">
	      <br>
	      <pre>mvn install playn</pre>
	    </li>
	    <li>And Go fork my messy demo!
	      <br>
	      <code>（╯°□°）╯︵ ┻━┻</code>
	      <br>
	      <pre>git clone https://code.googlecode.com/p/playn101/</pre>
	    </li>
	  </ul>
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>One more thing<h3>
	    <p class="build" style="text-align: center;">
		<img class="centered" style="margin-top: 200px;" src="/static/images/android_vector.jpg" height="50px">
	        <a href="/static/playn101-android-1.0-SNAPSHOT.apk">playn101-android-1.0-SNAPSHOT.apk</a>
	    </p>
	</h2>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

      <article>
	<h3>
	Thanks!
	</h3>
	<p>
	  <ul>
	    <li>Johan Euphrosine &lt;proppy&#64;google.com&gt;</li>
	    <li><a href="https://profiles.google.com/proppy">profiles.google.com/proppy</a></li>
	    <li><a href="https://developers.google.com/playn">developers.google.com/playn</a></li>
	    <b>Let's meet in Office Hours</b>
	  </ul>
	</p>
	<a class="selflink" href="http://proppy-playn101.appspot.com/">proppy-playn101.appspot.com</a>
      </article>

    </section>
    
    <div id="playn-container">
      <div id="playn-root"></div>
    </div>
    <script src='playn101/playn101.nocache.js'></script>

  </body>
</html>
